#pragma once

#include <lcir/ADT/ListNode.h>
#include <type_traits>
namespace lcir {
/// TODO: 目前存在一些问题，const迭代器构造函数需要将参数进行const_cast转换
/// 后序考虑像stl迭代器一样搞一个itwrap
template <class NodeTy, bool IsReverse, bool IsConst> class IListIterator {
public:
  using trait = listnode::detail::Trait<NodeTy, IsConst>;
  using access = listnode::detail::Accessor<NodeTy, IsConst>;
  using pointer = typename trait::pointer;
  using reference = typename trait::reference;
  friend class IListIterator<NodeTy, !IsReverse, IsConst>;
  friend class IListIterator<NodeTy, IsReverse, !IsConst>;
  friend class IListIterator<NodeTy, !IsReverse, !IsConst>;

private:
  using itTy = ListNodeBase<NodeTy> *;
  using nodePointer = typename trait::nodePointer;
  using nodeReference = typename trait::nodeReference;
  itTy nodePtr{nullptr};

public:
  IListIterator() = default;
  explicit IListIterator(pointer ptr) { nodePtr = ptr; }
  explicit IListIterator(reference ref) { nodePtr = &ref; }
  // explicit IListIterator(nodePointer nptr) { nodePtr = nptr; }
  explicit IListIterator(nodeReference nref) {
    nodePtr = const_cast<ListNodeBase<NodeTy> *>(&nref);
  }

  /// 拷贝构造，可以将常量迭代器指向非常量迭代器
  template <bool rhsIsConst>
  IListIterator(const IListIterator<NodeTy, IsReverse, rhsIsConst> &rhs,
                std::enable_if_t<IsConst || !rhsIsConst, void *> = nullptr)
      : nodePtr(rhs.nodePtr) {}

  /// 拷贝赋值，可以将常量迭代器指向非常量迭代器
  template <bool rhsIsConst>
  std::enable_if_t<IsConst || !rhsIsConst, IListIterator &>
  operator=(const IListIterator<NodeTy, IsReverse, rhsIsConst> &rhs) {
    nodePtr = rhs.nodePtr;
    return *this;
  }

  /// 反向正向迭代器互相赋值
  explicit IListIterator(const IListIterator<NodeTy, !IsReverse, IsConst> &rhs)
      : IListIterator(++rhs.getReverse()) {}

  IListIterator<NodeTy, !IsReverse, IsConst> getReverse() const {
    if (nodePtr)
      return IListIterator<NodeTy, !IsReverse, IsConst>(nodePtr);
    return IListIterator<NodeTy, !IsReverse, IsConst>();
  }

  /// 比较运算
  friend bool operator==(const IListIterator &lhs, const IListIterator &rhs) {
    return lhs.nodePtr == rhs.nodePtr;
  }

  friend bool operator!=(const IListIterator &lhs, const IListIterator &rhs) {
    return lhs.nodePtr != rhs.nodePtr;
  }

  /// 解引用
  reference operator*() const { return *static_cast<NodeTy *>(nodePtr); }
  pointer operator->() const { return &operator*(); }

  /// 递增和递减
  IListIterator &operator--() {
    nodePtr = IsReverse ? nodePtr->getNext() : nodePtr->getPrev();
    return *this;
  }
  IListIterator &operator++() {
    nodePtr = IsReverse ? nodePtr->getPrev() : nodePtr->getNext();
    return *this;
  }
  IListIterator operator--(int) {
    auto temp = *this;
    --*this;
    return temp;
  }
  IListIterator operator++(int) {
    auto temp = *this;
    ++*this;
    return temp;
  }
  /// 返回所持有的节点
  pointer getNode() const { return &operator*(); }
};
} // namespace lcir